﻿using CLM.Gestao.Administrador.BLL;
using CLM.Gestao.Administrador.DAL;
using CLM.Gestao.Importacao;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace CLM.Gestao.Custos.BLL
{
    /// <summary>
    /// 
    /// </summary>
    public class Custo
    {
        #region Processos

        private DataSet dsCustos;

        private Importacao.Excel ExcelConnection;

        #region Importar Custos

        /// <summary>
        /// 
        /// </summary>
        private enum TipoProcesso
        {
            BadGoodsExpenses,
            BadGoodsAllowances,
            ImportDuties,
            InboundFreightInsurance,
            AmostrasInvoices,
            TaxOverThirdParty,
            NominalPPVCompras,
            AmostrasCompras,
            LocalQARework,
            NominalPPVOrdemProducao,
            AmostrasOrdemProducao
        }

        #region Destruição: Bad Goods Expenses

        /// <summary>
        /// Bad Goods Expenses
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarBadGoodsExpenses(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutBadGoodsExpenses(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Bad Goods Expenses..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas B, Y, AA, AC, AE, AG
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0'),
                                       CustoDestruicao =
                                            Convert.ToDecimal(c.Field<object>("Quantidade"))
                                            * (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       CustoUnitario = (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0')].IdProduto,
                                       ImpostosIncineracao =
                                            Convert.ToDecimal(c.Field<object>("Vlr# ICMS"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# IPI"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# PIS"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# Cofins"))
                                            + Convert.ToDecimal(c.Field<object>("C# INCINER#")),
                                       Quantidade = Convert.ToDecimal(c.Field<object>("Quantidade")),
                                       ValorLancamento =
                                            ((Convert.ToDecimal(c.Field<object>("Quantidade"))
                                            * (decimal)(vl != null ? vl.ValorCustoUnitario : 0))
                                            + (Convert.ToDecimal(c.Field<object>("Vlr# ICMS"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# IPI"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# PIS"))
                                            + Convert.ToDecimal(c.Field<object>("Vlr# Cofins"))
                                            + Convert.ToDecimal(c.Field<object>("C# INCINER#"))))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.BadGoodsExpenses);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Bad Goods Expenses
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutBadGoodsExpenses(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Produto"); }
                catch { throw new Exception("A coluna (\"Produto\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Vlr# ICMS"); }
                catch { throw new Exception("A coluna (\"Vlr ICMS\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Vlr# IPI"); }
                catch { throw new Exception("A coluna (\"Vlr IPI\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Vlr# PIS"); }
                catch { throw new Exception("A coluna (\"Vlr PIS\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Vlr# Cofins"); }
                catch { throw new Exception("A coluna (\"Vlr Cofins\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("C# INCINER#"); }
                catch { throw new Exception("A coluna (\"C INCINER\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Quantidade"); }
                catch { throw new Exception("A coluna (\"Quantidade\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Destruição: Bad Goods Expenses

        #region Reserva: Bad Goods Allowances

        /// <summary>
        /// Bad Goods Allowances
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarBadGoodsAllowances(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutBadGoodsAllowances(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Bad Goods Allowances..."));

                Lancamento Lancamento = new Lancamento();

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas A, J, K
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("CODIGO")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("CODIGO")).PadLeft(9, '0'),
                                       CustoDestruicao =
                                            Convert.ToDecimal(c.Field<object>("QTDE"))
                                            * (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       CustoUnitario = (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("CODIGO")).PadLeft(9, '0')].IdProduto,
                                       ImpostosIncineracao =
                                            Convert.ToDecimal(c.Field<object>("Impostos"))
                                           + Convert.ToDecimal(c.Field<object>("C# INCINER#")),
                                       Quantidade = Convert.ToDecimal(c.Field<object>("QTDE")),
                                       ValorLancamento =
                                            ((Convert.ToDecimal(c.Field<object>("QTDE"))
                                            * (decimal)((vl != null ? vl.ValorCustoUnitario : 0)))
                                            + (Convert.ToDecimal(c.Field<object>("Impostos"))
                                            + Convert.ToDecimal(c.Field<object>("C# INCINER#"))))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.BadGoodsAllowances);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Bad Goods Allowances
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutBadGoodsAllowances(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("CODIGO"); }
                catch { throw new Exception("A coluna (\"CODIGO\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Impostos"); }
                catch { throw new Exception("A coluna (\"Impostos\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("QTDE"); }
                catch { throw new Exception("A coluna (\"QTDE\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("C# INCINER#"); }
                catch { throw new Exception("A coluna (\"C INCINER\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Reserva: Bad Goods Allowances

        #region Invoices: Import Duties e Inbound Freight & Insurance

        #region Import Duties

        /// <summary>
        /// Import Duties
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarImportDuties(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutImportDuties(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Import Duties..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Período do mês de importação
                Periodo Periodo = new Periodo();
                var MesPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().DescricaoPeriodo.Substring(0, 3);
                var AnoPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().AnoPeriodo.ToString().Substring(2, 2);

                // Colunas A, B, O
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0') equals db.CodigoProduto
                                   where Convert.ToString(c.Field<object>("MÊS")) == MesPeriodo + "/" + AnoPeriodo
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0'),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0')].IdProduto,
                                       ValorLancamento = Convert.ToDecimal(c.Field<object>("TAX"))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.ImportDuties);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Import Duties
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutImportDuties(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("MÊS"); }
                catch { throw new Exception("A coluna (\"MÊS\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Código_Nacional"); }
                catch { throw new Exception("A coluna (\"Código Nacional\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("TAX"); }
                catch { throw new Exception("A coluna (\"TAX\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Import Duties

        #region Inbound Freight & Insurance

        /// <summary>
        /// Inbound Freight & Insurance
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarInboundFreightInsurance(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutInboundFreightInsurance(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Inbound Freight & Insurance..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Período do mês de importação
                Periodo Periodo = new Periodo();
                var MesPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().DescricaoPeriodo.Substring(0, 3);
                var AnoPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().AnoPeriodo.ToString().Substring(2, 2);

                // Colunas A, B, M, N, Q, R, U
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0') equals db.CodigoProduto
                                   where Convert.ToString(c.Field<object>("MÊS")) == MesPeriodo + "/" + AnoPeriodo
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0'),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0')].IdProduto,
                                       ValorLancamento =
                                            Convert.ToDecimal(c.Field<object>("INSURANCE"))
                                            + Convert.ToDecimal(c.Field<object>("Freight Internat#"))
                                            + Convert.ToDecimal(c.Field<object>("Freight Nacional"))
                                            + Convert.ToDecimal(c.Field<object>("Customs Clearence"))
                                            + Convert.ToDecimal(c.Field<object>("Freight and pallets"))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.InboundFreightInsurance);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Inbound Freight & Insurance
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutInboundFreightInsurance(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("MÊS"); }
                catch { throw new Exception("A coluna (\"MÊS\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Código_Nacional"); }
                catch { throw new Exception("A coluna (\"Código Nacional\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("INSURANCE"); }
                catch { throw new Exception("A coluna (\"INSURANCE\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Freight Internat#"); }
                catch { throw new Exception("A coluna (\"Freight Internat.\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Freight Nacional"); }
                catch { throw new Exception("A coluna (\"Freight Nacional\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Customs Clearence"); }
                catch { throw new Exception("A coluna (\"Customs Clearence\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Freight and pallets"); }
                catch { throw new Exception("A coluna (\"Freight and pallets\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("TP"); }
                catch { throw new Exception("A coluna (\"TP\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Inbound Freight & Insurance

        #region Calcular Amostras de Invoices

        /// <summary>
        /// Calcula Amostras de Invoices
        /// </summary>
        /// <param name="pFileName">Arquivo a ser calculado as amostras</param>
        /// <param name="pMes">Mês a ser calculado</param>
        /// <param name="pAno">Ano a ser calculado</param>
        public void CalcularAmostrasInvoices(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT Código_Nacional, TP FROM [Dados$]");

                OnImportData(this, new ImportDataEventArgs("Calculando Amostras de Invoices..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas C, D, F
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals  vl.CodigoProduto
                                   where Convert.ToString(c.Field<object>("Código_Nacional")).Substring(0, 3) == "307"
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0'),
                                       CustoUnitario = vl != null ? vl.ValorCustoUnitario : 0,
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Código_Nacional")).PadLeft(9, '0')].IdProduto,
                                       Quantidade = Convert.ToDecimal(c.Field<object>("TP")),
                                       ValorLancamento = Convert.ToDecimal(c.Field<object>("TP")) * (vl != null ? vl.ValorCustoUnitario : 0)
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.AmostrasInvoices);

                OnImportData(this, new ImportDataEventArgs("Amostra calculada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion Calcular Amostras de Invoices

        #endregion Invoices: Import Duties e Inbound Freight & Insurance

        #region Compras: Tax Over – Third Party e Nominal PPV – Third Party

        #region Tax Over – Third Party

        /// <summary>
        /// Tax Over – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarTaxOverThirdParty(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutTaxOverThirdParty(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Tax Over – Third Party..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Colunas B, D, K, L, M
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0') equals db.CodigoProduto
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0'),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0')].IdProduto,
                                       ValorLancamento =
                                            Convert.ToDecimal(c.Field<object>("Icms"))
                                            + Convert.ToDecimal(c.Field<object>("Icms ST"))
                                            + Convert.ToDecimal(c.Field<object>("IPI"))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.TaxOverThirdParty);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Tax Over – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutTaxOverThirdParty(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Item Nac"); }
                catch { throw new Exception("A coluna (\"Item Nac\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Icms"); }
                catch { throw new Exception("A coluna (\"Icms\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Icms ST"); }
                catch { throw new Exception("A coluna (\"Icms ST\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("IPI"); }
                catch { throw new Exception("A coluna (\"IPI\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Tax Over – Third Party

        #region Nominal PPV – Third Party

        /// <summary>
        /// Nominal PPV – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarNominalPPVCompras(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutNominalPPVCompras(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Nominal PPV – Third Party..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas D, H, N
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0'),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0')].IdProduto,
                                       ValorLancamento =
                                            (((Convert.ToDecimal(c.Field<object>("Custo STD"))
                                            / Convert.ToDecimal(c.Field<object>("Qtde")))
                                            - (decimal)(vl != null ? vl.ValorCustoUnitario : 0))
                                            * Convert.ToDecimal(c.Field<object>("Qtde")))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.NominalPPVCompras);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout Nominal PPV – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutNominalPPVCompras(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Item Nac"); }
                catch { throw new Exception("A coluna (\"Item Nac\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Qtde"); }
                catch { throw new Exception("A coluna (\"Qtde\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Custo STD"); }
                catch { throw new Exception("A coluna (\"Custo STD\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Nominal PPV – Third Party

        #region Calcular Amostras de Compras

        /// <summary>
        /// Calcula Amostras de Compras
        /// </summary>
        /// <param name="pFileName">Arquivo a ser calculado as amostras</param>
        /// <param name="pMes">Mês a ser calculado</param>
        /// <param name="pAno">Ano a ser calculado</param>
        public void CalcularAmostrasCompras(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]");

                OnImportData(this, new ImportDataEventArgs("Calculando Amostras de Compras..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas C, D, F
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   where Convert.ToString(c.Field<object>("Item Nac")).Substring(0, 3) == "007"
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0'),
                                       CustoUnitario = (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Item Nac")).PadLeft(9, '0')].IdProduto,
                                       Quantidade = Convert.ToDecimal(c.Field<object>("Qtde")),
                                       ValorLancamento =
                                            Convert.ToDecimal(c.Field<object>("Qtde"))
                                            * (decimal)(vl != null ? vl.ValorCustoUnitario : 0)
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.AmostrasCompras);

                OnImportData(this, new ImportDataEventArgs("Amostra calculada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion Calcular Amostras de Compras

        #endregion Compras: Tax Over – Third Party e Nominal PPV – Third Party

        #region Ordem de Produção: Local QA, Rework e Nominal PPV – Third Party

        #region Local QA, Rework

        /// <summary>
        /// Local QA, Rework
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarLocalQARework(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutLocalQARework(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Local QA, Rework..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Colunas B, C, D
                var ProdutosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                     join db in Produtos.Select(s => s.Value).ToList()
                                     on Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0') equals db.CodigoProduto
                                     where Convert.ToString(c.Field<object>(@"Tipo RE/DE")) == "PR0"
                                     select new Lista
                                    {
                                        CodigoProduto = Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0'),
                                        OrdemProducao = Convert.ToString(c.Field<object>("Ord Producao"))
                                    }).ToList();

                // Colunas B, D, I
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join p in ProdutosExcel
                                   on Convert.ToString(c.Field<object>("Ord Producao")) equals p.OrdemProducao
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on p.CodigoProduto equals db.CodigoProduto
                                   where (Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "111"
                                        || Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "021"
                                        || Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "099")
                                        && (p.CodigoProduto.Substring(0, 3) == "003"
                                        || p.CodigoProduto.Substring(0, 3) == "103"
                                        || p.CodigoProduto.Substring(0, 3) == "106"
                                        || p.CodigoProduto.Substring(0, 3) == "107")
                                   select new Lista
                                   {
                                       CodigoProduto = p.CodigoProduto,
                                       IdProduto = Produtos[p.CodigoProduto].IdProduto,
                                       ValorLancamento = Convert.ToDecimal(c.Field<object>("Custo Total"))
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.LocalQARework);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout de Local QA, Rework
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutLocalQARework(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Ord Producao"); }
                catch { throw new Exception("A coluna (\"Ord Producao\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>(@"Tipo RE/DE"); }
                catch { throw new Exception("A coluna (\"Tipo RE/DE\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Produto"); }
                catch { throw new Exception("A coluna (\"Produto\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Custo Total"); }
                catch { throw new Exception("A coluna (\"Custo Total\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Local QA, Rework

        #region Nominal PPV – Third Party

        /// <summary>
        /// Nominal PPV – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        public void ImportarNominalPPVOrdemProducao(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = null;

                ValidaLayoutNominalPPVOrdemProducao(pFileName);

                OnImportData(this, new ImportDataEventArgs("Importando informações de Nominal PPV – Third Party..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas C, D, F, I
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   where Convert.ToString(c.Field<object>(@"Tipo RE/DE")) == "PR0"
                                        && (Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "006"
                                        || Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "007")
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0'),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0')].IdProduto,
                                       ValorLancamento = Convert.ToDecimal(c.Field<object>("Quantidade")) != 0 ?
                                            (((Convert.ToDecimal(c.Field<object>("Custo Total"))
                                            / Convert.ToDecimal(c.Field<object>("Quantidade")))
                                            - (decimal)(vl != null ? vl.ValorCustoUnitario : 0))
                                            * Convert.ToDecimal(c.Field<object>("Quantidade"))) : 0
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.NominalPPVOrdemProducao);

                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Valida Layout Nominal PPV – Third Party
        /// </summary>
        /// <param name="pFileName">Arquivo a ser importado</param>
        private void ValidaLayoutNominalPPVOrdemProducao(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsCustos != null && dsCustos.Tables != null && dsCustos.Tables.Count > 0 && dsCustos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>(@"Tipo RE/DE"); }
                catch { throw new Exception("A coluna (\"Tipo RE/DE\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Produto"); }
                catch { throw new Exception("A coluna (\"Produto\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Quantidade"); }
                catch { throw new Exception("A coluna (\"Quantidade\") não foi encontrada no arquivo."); }

                try { var aux = dsCustos.Tables[0].Rows[0].Field<object>("Custo Total"); }
                catch { throw new Exception("A coluna (\"Custo Total\") não foi encontrada no arquivo."); }
            }
        }

        #endregion Nominal PPV – Third Party

        #region Calcular Amostras de Ordem de Produção

        /// <summary>
        /// Calcula Amostras de Ordem de Produção
        /// </summary>
        /// <param name="pFileName">Arquivo a ser calculado as amostras</param>
        /// <param name="pMes">Mês a ser calculado</param>
        /// <param name="pAno">Ano a ser calculado</param>
        public void CalcularAmostrasOrdemProducao(string pFileName, int pMes, int pAno)
        {
            try
            {
                ExcelConnection = new Importacao.Excel();
                dsCustos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]");

                OnImportData(this, new ImportDataEventArgs("Calculando Amostras de Ordem de Produção..."));

                // Dictionary de Produtos para recuperar o ID, utilizando o código
                Produto Produto = new Produto();
                var Produtos = Produto.GetItens().ToDictionary(d => d.CodigoProduto);

                // Dictionary de Custos Unitários para recuperar o valor, utilizando o código
                CustoUnitario CustoUnitario = new CustoUnitario();
                var ValoresCustosUnitarios = CustoUnitario.GetLista();

                // Colunas C, D, F
                var CustosExcel = (from c in dsCustos.Tables[0].AsEnumerable()
                                   join db in Produtos.Select(s => s.Value).ToList()
                                   on Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0') equals db.CodigoProduto
                                   join vl in ValoresCustosUnitarios
                                   on db.CodigoProduto equals vl.CodigoProduto
                                   where Convert.ToString(c.Field<object>(@"Tipo RE/DE")) == "PR0"
                                        && (Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "003"
                                        || Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "007"
                                        || Convert.ToString(c.Field<object>("Produto")).Substring(0, 3) == "103")
                                   select new Lista
                                   {
                                       CodigoProduto = Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0'),
                                       CustoUnitario = (decimal)(vl != null ? vl.ValorCustoUnitario : 0),
                                       IdProduto = Produtos[Convert.ToString(c.Field<object>("Produto")).PadLeft(9, '0')].IdProduto,
                                       Quantidade = Convert.ToDecimal(c.Field<object>("Quantidade")),
                                       ValorLancamento =
                                            Convert.ToDecimal(c.Field<object>("Quantidade"))
                                            * (decimal)(vl != null ? vl.ValorCustoUnitario : 0)
                                   }).ToList();

                ProcessarCustos(CustosExcel, pMes, pAno, TipoProcesso.AmostrasOrdemProducao);

                OnImportData(this, new ImportDataEventArgs("Amostra calculada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion Calcular Amostras de Ordem de Produção

        #endregion Ordem de Produção: Local QA, Rework e Nominal PPV – Third Party

        /// <summary>
        /// Processa Custos
        /// </summary>
        /// <param name="pListaCustos">Lista de Custos</param>
        /// <param name="pTipoProcesso">Tipo de processo a ser executado</param>
        private void ProcessarCustos(List<Lista> pListaCustos, int pMes, int pAno, TipoProcesso pTipoProcesso)
        {
            OnImportData(this, new ImportDataEventArgs("Validando dados..."));

            Lancamento Lancamento = new Lancamento();
            LancamentoCustoHistorico LancamentoCustoHistorico = new LancamentoCustoHistorico();

            // Dictionary de Produtos para recuperar o ID, utilizando o código
            Produto Produto = new Produto();
            var Produtos = Produto.GetLista().ToDictionary(d => d.CodigoProduto);
            
            // Período do mês de importação
            Periodo Periodo = new Periodo();
            var IdPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().IdPeriodo;

            // Dictionary de Contas Contábeis para recuperar o ID, utilizando o código e a descrição
            ContaContabil ContaContabil = new ContaContabil();
            var CodigosContasContabeis = ContaContabil.GetItens(new ContaContabil.Lista() { IndicaGerencial = false }).GroupBy(g => g.CodigoContaContabil).Select(s => new ContaContabil.Lista { CodigoContaContabil = s.Key, IdContaContabil = s.FirstOrDefault().IdContaContabil }).ToDictionary(d => d.CodigoContaContabil);
            var DescricoesContasContabeis = ContaContabil.GetItens(new ContaContabil.Lista() { IndicaGerencial = true }).GroupBy(g => g.DescricaoContaContabil).Select(s => new ContaContabil.Lista { DescricaoContaContabil = s.Key, IdContaContabil = s.FirstOrDefault().IdContaContabil }).ToDictionary(d => d.DescricaoContaContabil);

            // Dictionary de Centros de Custos para recuperar o ID, utilizando o ID
            CentroCusto CentroCusto = new CentroCusto();
            var CentrosCustos = CentroCusto.GetLista(new CentroCusto.Lista() { IndicaGerencial = false }).ToDictionary(d => d.IdCentroCusto);

            // Dictionary de Indicadores de Custos para recuperar o ID, utilizando o nome
            IndicadorCusto IndicadorCusto = new IndicadorCusto();
            var IndicadoresCustos = IndicadorCusto.GetLista().ToDictionary(d => d.NomeIndicadorCusto);

            // Dictionary de Indicadores de Despesas para recuperar o ID, utilizando o nome
            IndicadorDespesa IndicadorDespesa = new IndicadorDespesa();
            var IndicadoresDespesas = IndicadorDespesa.GetLista().ToDictionary(d => d.NomeIndicadorDespesa);
            
            ValidaDadosImportacao(Produtos, pListaCustos);

            OnImportData(this, new ImportDataEventArgs("Validação completa..."));

            ExcluirLancamentosAnteriores(pMes, pAno, pTipoProcesso);

            OnImportData(this, new ImportDataEventArgs("Iniciando processo..."));

            if (pTipoProcesso == TipoProcesso.BadGoodsExpenses)
            {
                #region Bad Goods Expenses

                var Lancamentos = (from c in pListaCustos
                                   select new TB_LANCAMENTO
                                   {
                                       CONTRATO_DESPESA_COMPROMETIDA = null,
                                       DATA_INCLUSAO = DateTime.Now,
                                       DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                       DESCRICAO_LANCAMENTO = string.Format("Saldo de custos do período {0}/{1}", pMes, pAno),
                                       ID_CENTRO_CUSTO = null,
                                       ID_CONTA_CONTABIL = DescricoesContasContabeis[Indicadores.IndicadoresCustos.BadGoodsExpenses].IdContaContabil,
                                       ID_LANCAMENTO_TIPO = 1,
                                       ID_MAPA_ESTRATEGICO_ITEM = null,
                                       ID_PERIODO = IdPeriodo,
                                       ID_PROJETO = null,
                                       INDICA_DESPESA_COMPROMETIDA = false,
                                       VALOR_LANCAMENTO = c.ValorLancamento,
                                       TB_LANCAMENTO_CUSTO = new TrackableCollection<TB_LANCAMENTO_CUSTO>()
                                   {
                                       new TB_LANCAMENTO_CUSTO()
                                       {
                                           ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.BadGoodsExpenses].IdIndicadorCusto,
                                           ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                                   }).ToList();

                int i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.BadGoodsExpenses + "...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Bad Goods Expenses
            }

            if (pTipoProcesso == TipoProcesso.BadGoodsAllowances)
            {
                #region Bad Goods Allowances

                var Lancamentos = (from c in pListaCustos
                                   select new TB_LANCAMENTO
                                   {
                                       CONTRATO_DESPESA_COMPROMETIDA = null,
                                       DATA_INCLUSAO = DateTime.Now,
                                       DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                       DESCRICAO_LANCAMENTO = string.Format("Saldo de custos do período {0}/{1}", pMes, pAno),
                                       ID_CENTRO_CUSTO = null,
                                       ID_CONTA_CONTABIL = DescricoesContasContabeis[Indicadores.IndicadoresCustos.BadGoodsAllowances].IdContaContabil,
                                       ID_LANCAMENTO_TIPO = 1,
                                       ID_MAPA_ESTRATEGICO_ITEM = null,
                                       ID_PERIODO = IdPeriodo,
                                       ID_PROJETO = null,
                                       INDICA_DESPESA_COMPROMETIDA = false,
                                       VALOR_LANCAMENTO = c.ValorLancamento,
                                       TB_LANCAMENTO_CUSTO = new TrackableCollection<TB_LANCAMENTO_CUSTO>()
                                   {
                                       new TB_LANCAMENTO_CUSTO()
                                       {
                                           ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.BadGoodsAllowances].IdIndicadorCusto,
                                           ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                                   }).ToList();

                int i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.BadGoodsAllowances + "...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Bad Goods Allowances
            }

            if (pTipoProcesso == TipoProcesso.ImportDuties)
            {
                #region Import Duties

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.ImportDuties].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.ImportDuties + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Import Duties

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.ImportDuties].IdIndicadorCusto, Indicadores.IndicadoresCustos.ImportDuties, DescricoesContasContabeis[Indicadores.IndicadoresCustos.ImportDuties].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.InboundFreightInsurance)
            {
                #region Inbound Freight & Insurance

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.InboundFreightInsurance].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.InboundFreightInsurance + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Inbound Freight & Insurance

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.InboundFreightInsurance].IdIndicadorCusto, Indicadores.IndicadoresCustos.InboundFreightInsurance, DescricoesContasContabeis[Indicadores.IndicadoresCustos.InboundFreightInsurance].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.AmostrasInvoices)
            {
                #region Inclui os produtos iniciados em 307 na conta contábil 07001
                //TODO: Hard code no ID_LANCAMENTO_TIPO
                var Lancamentos = (from c in pListaCustos
                                   select new TB_LANCAMENTO
                                   {
                                       CONTRATO_DESPESA_COMPROMETIDA = null,
                                       DATA_INCLUSAO = DateTime.Now,
                                       DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                       DESCRICAO_LANCAMENTO = string.Format("Amostra de Invoices do período {0}/{1}", pMes, pAno),
                                       ID_CENTRO_CUSTO = Produtos[c.CodigoProduto].IdCentroCusto,
                                       ID_CONTA_CONTABIL = CodigosContasContabeis["34107001"].IdContaContabil,
                                       ID_LANCAMENTO_TIPO = 6,
                                       ID_MAPA_ESTRATEGICO_ITEM = null,
                                       ID_PERIODO = IdPeriodo,
                                       ID_PROJETO = null,
                                       INDICA_DESPESA_COMPROMETIDA = false,
                                       VALOR_LANCAMENTO = c.ValorLancamento,
                                       TB_LANCAMENTO_DESPESA = new TrackableCollection<TB_LANCAMENTO_DESPESA>()
                                   {
                                       new TB_LANCAMENTO_DESPESA()
                                       {
                                           ID_INDICADOR_DESPESA = (int)IndicadoresDespesas[Indicadores.IndicadoresDespesas.Despesas].IdIndicadorDespesa,
                                           ID_PRODUTO =  Produtos[c.CodigoProduto].IdProdutoPai != null ? Produtos[c.CodigoProduto].IdProdutoPai : Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                                   }).ToList();

                int i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo amostra de Invoices...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Inclui os produtos iniciados em 307 na conta contábil 07001
            }

            if (pTipoProcesso == TipoProcesso.TaxOverThirdParty)
            {
                #region Tax Over – Third Party

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.TaxOverThirdParty].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.TaxOverThirdParty + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Tax Over – Third Party

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.TaxOverThirdParty].IdIndicadorCusto, Indicadores.IndicadoresCustos.TaxOverThirdParty, DescricoesContasContabeis[Indicadores.IndicadoresCustos.TaxOverThirdParty].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.NominalPPVCompras)
            {
                #region Nominal PPV – Third Party

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVCompras].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.NominalPPVCompras + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Nominal PPV – Third Party

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVCompras].IdIndicadorCusto, Indicadores.IndicadoresCustos.NominalPPVCompras, DescricoesContasContabeis[Indicadores.IndicadoresCustos.NominalPPVCompras].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.AmostrasCompras)
            {
                #region Inclui os produtos iniciados em 007 na conta contábil 07001
                //TODO: Hard code no ID_LANCAMENTO_TIPO
                var Lancamentos = (from c in pListaCustos
                                   select new TB_LANCAMENTO
                                   {
                                       CONTRATO_DESPESA_COMPROMETIDA = null,
                                       DATA_INCLUSAO = DateTime.Now,
                                       DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                       DESCRICAO_LANCAMENTO = string.Format("Amostra de Compras do período {0}/{1}", pMes, pAno),
                                       ID_CENTRO_CUSTO = Produtos[c.CodigoProduto].IdCentroCusto,
                                       ID_CONTA_CONTABIL = CodigosContasContabeis["34107001"].IdContaContabil,
                                       ID_LANCAMENTO_TIPO = 7,
                                       ID_MAPA_ESTRATEGICO_ITEM = null,
                                       ID_PERIODO = IdPeriodo,
                                       ID_PROJETO = null,
                                       INDICA_DESPESA_COMPROMETIDA = false,
                                       VALOR_LANCAMENTO = c.ValorLancamento,
                                       TB_LANCAMENTO_DESPESA = new TrackableCollection<TB_LANCAMENTO_DESPESA>()
                                   {
                                       new TB_LANCAMENTO_DESPESA()
                                       {
                                           ID_INDICADOR_DESPESA = (int)IndicadoresDespesas[Indicadores.IndicadoresDespesas.Despesas].IdIndicadorDespesa,
                                           ID_PRODUTO = Produtos[c.CodigoProduto].IdProdutoPai != null ? Produtos[c.CodigoProduto].IdProdutoPai : Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                                   }).ToList();

                int i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo amostra de Compras...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Inclui os produtos iniciados em 007 na conta contábil 07001
            }

            if (pTipoProcesso == TipoProcesso.LocalQARework)
            {
                #region Local QA, Rework

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.LocalQARework].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.LocalQARework + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Local QA, Rework

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.LocalQARework].IdIndicadorCusto, Indicadores.IndicadoresCustos.LocalQARework, DescricoesContasContabeis[Indicadores.IndicadoresCustos.LocalQARework].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.NominalPPVOrdemProducao)
            {
                #region Nominal PPV – Third Party

                var LancamentosCustosHistorico = (from c in pListaCustos
                                                  select new TB_LANCAMENTO_CUSTO_HISTORICO
                                                  {
                                                      ID_INDICADOR_CUSTO = (int)IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVOrdemProducao].IdIndicadorCusto,
                                                      ID_PERIODO = IdPeriodo,
                                                      ID_PRODUTO = Produtos[c.CodigoProduto].IdProduto,
                                                      VALOR_LANCAMENTO = c.ValorLancamento
                                                  }).ToList();

                int i = 0;
                foreach (var item in LancamentosCustosHistorico)
                {
                    LancamentoCustoHistorico.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo indicador " + Indicadores.IndicadoresCustos.NominalPPVOrdemProducao + "...", i, LancamentosCustosHistorico.Count()));
                }
                LancamentoCustoHistorico.Save();

                #endregion Nominal PPV – Third Party

                CalcularGiroEstoque(pMes, pAno, (int)IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVOrdemProducao].IdIndicadorCusto, Indicadores.IndicadoresCustos.NominalPPVOrdemProducao, DescricoesContasContabeis[Indicadores.IndicadoresCustos.NominalPPVOrdemProducao].IdContaContabil);
            }

            if (pTipoProcesso == TipoProcesso.AmostrasOrdemProducao)
            {
                #region Inclui os produtos iniciados em 003 e 103 na conta contábil 09001
                //TODO: Hard code no ID_LANCAMENTO_TIPO
                var Lancamentos = (from c in pListaCustos
                                   where c.CodigoProduto.Substring(0, 3) == "003" || c.CodigoProduto.Substring(0, 3) == "103"
                                   select new TB_LANCAMENTO
                                   {
                                       CONTRATO_DESPESA_COMPROMETIDA = null,
                                       DATA_INCLUSAO = DateTime.Now,
                                       DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                       DESCRICAO_LANCAMENTO = string.Format("Amostra de Ordem de Produção do período {0}/{1}", pMes, pAno),
                                       ID_CENTRO_CUSTO = Produtos[c.CodigoProduto].IdCentroCusto,
                                       ID_CONTA_CONTABIL = CodigosContasContabeis["34109001"].IdContaContabil,
                                       ID_LANCAMENTO_TIPO = 8,
                                       ID_MAPA_ESTRATEGICO_ITEM = null,
                                       ID_PERIODO = IdPeriodo,
                                       ID_PROJETO = null,
                                       INDICA_DESPESA_COMPROMETIDA = false,
                                       VALOR_LANCAMENTO = c.ValorLancamento,
                                       TB_LANCAMENTO_DESPESA = new TrackableCollection<TB_LANCAMENTO_DESPESA>()
                                   {
                                       new TB_LANCAMENTO_DESPESA()
                                       {
                                           ID_INDICADOR_DESPESA = (int)IndicadoresDespesas[Indicadores.IndicadoresDespesas.Despesas].IdIndicadorDespesa,
                                           ID_PRODUTO = Produtos[c.CodigoProduto].IdProdutoPai != null ? Produtos[c.CodigoProduto].IdProdutoPai : Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                                   }).ToList();

                int i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo amostra de Ordem de Produção...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Inclui os produtos iniciados em 003 e 103 na conta contábil 09001

                #region Inclui os produtos iniciados em 007 na conta contábil 07001
                //TODO: Hard code no ID_LANCAMENTO_TIPO
                Lancamentos = (from c in pListaCustos
                               where c.CodigoProduto.Substring(0, 3) == "007"
                               select new TB_LANCAMENTO
                               {
                                   CONTRATO_DESPESA_COMPROMETIDA = null,
                                   DATA_INCLUSAO = DateTime.Now,
                                   DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                   DESCRICAO_LANCAMENTO = string.Format("Amostra de Ordem de Produção do período {0}/{1}", pMes, pAno),
                                   ID_CENTRO_CUSTO = Produtos[c.CodigoProduto].IdCentroCusto,
                                   ID_CONTA_CONTABIL = CodigosContasContabeis["34107001"].IdContaContabil,
                                   ID_LANCAMENTO_TIPO = 8,
                                   ID_MAPA_ESTRATEGICO_ITEM = null,
                                   ID_PERIODO = IdPeriodo,
                                   ID_PROJETO = null,
                                   INDICA_DESPESA_COMPROMETIDA = false,
                                   VALOR_LANCAMENTO = c.ValorLancamento,
                                   TB_LANCAMENTO_DESPESA = new TrackableCollection<TB_LANCAMENTO_DESPESA>()
                                   {
                                       new TB_LANCAMENTO_DESPESA()
                                       {
                                           ID_INDICADOR_DESPESA = (int)IndicadoresDespesas[Indicadores.IndicadoresDespesas.Despesas].IdIndicadorDespesa,
                                           ID_PRODUTO = Produtos[c.CodigoProduto].IdProdutoPai != null ? Produtos[c.CodigoProduto].IdProdutoPai : Produtos[c.CodigoProduto].IdProduto
                                       }
                                    }
                               }).ToList();

                i = 0;
                foreach (var item in Lancamentos)
                {
                    Lancamento.Add(item);

                    i++;
                    OnImportData(this, new ImportDataEventArgs("Inserindo amostra de Ordem de Produção...", i, Lancamentos.Count()));
                }
                Lancamento.Save();

                #endregion Inclui os produtos iniciados em 007 na conta contábil 07001
            }
        }

        #region Calcular Giro de Estoque

        /// <summary>
        /// Calcula o Giro de Estoque
        /// </summary>
        /// <param name="pMes">Mês a ser importado</param>
        /// <param name="pAno">Ano a ser importado</param>
        /// <param name="pIdIndicadorCusto">ID do Indicador de Custo</param>
        /// <param name="pNomeIndicador">Nome do indicador a ser calculado</param>
        /// <param name="pIdContaContabil">ID da Conta Contábil</param>
        public void CalcularGiroEstoque(int pMes, int pAno, int pIdIndicadorCusto, string pNomeIndicador, int pIdContaContabil)
        {
            Periodo Periodo = new Periodo();
            int[] Periodos = Periodo.GetItens(new Periodo.Lista { OrderByDescending = true }).Where(w => (w.MesPeriodo <= pMes && w.AnoPeriodo == pAno) || w.AnoPeriodo < pAno).Take(5).Select(s => s.IdPeriodo).ToArray();

            LancamentoCustoHistorico LancamentoCustoHistorico = new LancamentoCustoHistorico();
            List<LancamentoCustoHistorico.Lista> Lancamentos = LancamentoCustoHistorico.GetLista(new LancamentoCustoHistorico.Lista() { IdPeriodos = Periodos.Skip(1).Take(4).ToArray(), IdIndicadorCusto = pIdIndicadorCusto });

            var NovosLancamentos = (from c in Lancamentos
                                    select new TB_LANCAMENTO
                                    {
                                        CONTRATO_DESPESA_COMPROMETIDA = null,
                                        DATA_INCLUSAO = DateTime.Now,
                                        DATA_LANCAMENTO = new DateTime(pAno, pMes, 1),
                                        DESCRICAO_LANCAMENTO = string.Format("Indicador {0} do período {1}/{2}", pNomeIndicador, pMes, pAno),
                                        ID_CENTRO_CUSTO = null,
                                        ID_CONTA_CONTABIL = pIdContaContabil,
                                        ID_LANCAMENTO_TIPO = 1,
                                        ID_MAPA_ESTRATEGICO_ITEM = null,
                                        ID_PERIODO = Periodos.First(),
                                        ID_PROJETO = null,
                                        INDICA_DESPESA_COMPROMETIDA = false,
                                        VALOR_LANCAMENTO = (c.ValorLancamento * (decimal)0.25),
                                        TB_LANCAMENTO_CUSTO = new TrackableCollection<TB_LANCAMENTO_CUSTO>()
                                        {
                                            new TB_LANCAMENTO_CUSTO()
                                            {
                                                ID_INDICADOR_CUSTO = pIdIndicadorCusto,
                                                ID_PRODUTO = c.IdProduto
                                            }
                                        }
                                    }).ToList();

            Lancamento Lancamento = new Lancamento();

            int i = 0;

            int contaLanc = 0; // Contador para evitar estouro de memória

            try
            {
                foreach (var item in NovosLancamentos)
                {
                    Lancamento.Add(item);

                    contaLanc++;
                    if (contaLanc == 2500)
                    {
                        Lancamento.Save();
                        contaLanc = 0;
                    }

                    if (OnImportData != null)
                    {
                        i++;
                        OnImportData(this, new ImportDataEventArgs("Inserindo giro de estoque de " + pNomeIndicador + "...", i, Lancamentos.Count()));
                    }
                }
            }
            catch (Exception ex)
            {
                Exportacao.Texto.LogErro(ex, "Calculando giro de estoque - CustoBLO");
                throw new Exception(ex.Message);
            }


            Lancamento.Save();
        }

        #endregion Calcular Giro de Estoque

        /// <summary>
        /// Valida Dados de Importação
        /// </summary>
        /// <param name="pProdutos">Produtos</param>
        /// <param name="pListaCustos">Lista de Custos</param>
        private void ValidaDadosImportacao(Dictionary<string, Produto.Lista> pProdutos, List<Lista> pListaCustos)
        {
            // Valida se os produtos estão cadastrados no sistema
            var Valida = (from p in pListaCustos
                          join db in pProdutos.Select(s => s.Value).ToList()
                          on p.CodigoProduto equals db.CodigoProduto
                          into produtos
                          from db in produtos.DefaultIfEmpty()
                          where db == null
                          select p).Count();

            if (Valida > 0)
                throw new Exception("Existem produtos não cadastrados no sistema.\nPor favor, execute a sincronização de produtos antes de importar os custos.");

            // Valida relacionamento entre Produto Protheus e Produto Galderma Global
            ProdutoGlobal ProdutoGlobal = new ProdutoGlobal();
            var ProdutosGlobais = ProdutoGlobal.GetLista().ToList();

            var ValidaRelacionamentosProdutos = (from p in pProdutos
                                                 join db in pListaCustos
                                                 on p.Value.CodigoProduto equals db.CodigoProduto
                                                 where string.IsNullOrWhiteSpace(p.Value.CodigoProdutoGlobal)
                                                 select p).Count();

            if (ValidaRelacionamentosProdutos > 0)
                throw new Exception("Existem produtos sem relacionamento entre Produto Protheus e Produto Galderma Global.");

            // Valida se existe valor de custo unitário
            CustoUnitario CustoUnitario = new CustoUnitario();
            var CustosUnitarios = CustoUnitario.GetLista();

            //TODO: este linq  serve somente para identificarmos os  produtos globais  que não contém custo unitário
            var CustosUnitario = from p in pListaCustos
                                         join db in CustosUnitarios
                                         on p.CodigoProduto.PadLeft(9, '0') equals db.CodigoProduto.PadLeft(9, '0')
                                         into custosUnitarios
                                         from db in custosUnitarios.DefaultIfEmpty()
                                         where db == null
                                         select p;


            var ValidaCustosUnitarios = (from p in pListaCustos
                                         join db in CustosUnitarios
                                         on p.CodigoProduto.PadLeft(9, '0') equals db.CodigoProduto.PadLeft(9, '0')
                                         into custosUnitarios
                                         from db in custosUnitarios.DefaultIfEmpty()
                                         where db == null
                                         select p).Count();

            if (ValidaCustosUnitarios > 0)
                throw new Exception("Existem produtos sem valor de custo unitário.");

            // Valida relacionamento entre o Produto e Produto Pai, se tipo é AG ou SEMI
            // Dictionary de Tipos de Produtos para recuperar o ID, utilizando o nome
            ProdutoTipo ProdutoTipo = new ProdutoTipo();
            var ProdutosTipos = ProdutoTipo.GetLista().ToDictionary(d => d.NomeProdutoTipo);

            Produto Produto = new Produto();
            var Produtos = Produto.GetLista().Where(w => w.IdProdutoTipo == ProdutosTipos["AG"].IdProdutoTipo || w.IdProdutoTipo == ProdutosTipos["SEMI"].IdProdutoTipo).ToList();

            var ValidaRelacionamentosTipos = (from p in pListaCustos
                                              join db in Produtos
                                              on p.CodigoProduto equals db.CodigoProduto
                                              where db.IdProdutoPai == null
                                              select p).Count();

            //if (ValidaRelacionamentosTipos > 0)
             //   throw new Exception("Existem produtos de AG ou SEMI sem relacionamento entre Produto e Produto Pai.");
        }

        /// <summary>
        /// Executa a limpeza da tabela de lançamentos para iniciar
        /// uma nova inserção sem duplicação de dados
        /// </summary>
        /// <param name="pMes">Mês para filtro dos lançamentos</param>
        /// <param name="pAno">Ano para filtro dos lançamentos</param>
        /// <param name="pTipoProcesso">Tipo de lançamento a ser excluído</param>
        private void ExcluirLancamentosAnteriores(int pMes, int pAno, TipoProcesso pTipoProcesso)
        {
            OnImportData(this, new ImportDataEventArgs("Excluindo lançamentos anteriores..."));

            // Período do mês de importação
            Periodo Periodo = new Periodo();
            var IdPeriodo = Periodo.GetItens(new Periodo.Lista() { AnoPeriodo = pAno, MesPeriodo = pMes }).First().IdPeriodo;

            // Dictionary de Indicador Custo para recuperar o ID, utilizando o nome
            IndicadorCusto IndicadorCusto = new IndicadorCusto();
            var IdIndicadorCusto = IndicadorCusto.GetLista(new IndicadorCusto.Lista()).ToDictionary(d => d.NomeIndicadorCusto);

            SPExcluirLancamentosAnterioresCustos ExcluirLancamentosAnterioresCustos = new SPExcluirLancamentosAnterioresCustos();
            SPExcluirLancamentosAnterioresAmostras ExcluirLancamentosAnterioresAmostras = new SPExcluirLancamentosAnterioresAmostras();
            
            if (pTipoProcesso == TipoProcesso.BadGoodsExpenses)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.BadGoodsExpenses].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.BadGoodsAllowances)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.BadGoodsAllowances].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.ImportDuties)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.ImportDuties].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.InboundFreightInsurance)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.InboundFreightInsurance].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.AmostrasInvoices)
                ExcluirLancamentosAnterioresAmostras.Execute(IdPeriodo, 6);

            if (pTipoProcesso == TipoProcesso.TaxOverThirdParty)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.TaxOverThirdParty].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.NominalPPVCompras)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.NominalPPVCompras].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.AmostrasCompras)
                ExcluirLancamentosAnterioresAmostras.Execute(IdPeriodo, 7);

            if (pTipoProcesso == TipoProcesso.LocalQARework)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.LocalQARework].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.NominalPPVOrdemProducao)
                ExcluirLancamentosAnterioresCustos.Execute(IdPeriodo, (int)IdIndicadorCusto[Indicadores.IndicadoresCustos.NominalPPVOrdemProducao].IdIndicadorCusto);

            if (pTipoProcesso == TipoProcesso.AmostrasOrdemProducao)
                ExcluirLancamentosAnterioresAmostras.Execute(IdPeriodo, 8);
        }

        #endregion Importar Custos

        #endregion Processos

        #region Classes

        /// <summary>
        /// Lista com as propriedades da classe
        /// </summary>
        public class Lista
        {
            public int IdProduto { get; set; }
            public string CodigoProduto { get; set; }
            public string OrdemProducao { get; set; }
            public decimal ImpostosIncineracao { get; set; }
            public decimal Quantidade { get; set; }
            public decimal CustoUnitario { get; set; }
            public decimal CustoDestruicao { get; set; }
            public decimal ValorLancamento { get; set; }
        }

        #endregion Classes

        public event ImportDataEventHandler OnImportData;
    }
}